home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: MegaDisc
/
MegaDisc 36 (1993-11)(MegaDisc Digital Publishing)(AU)(Disk 2 of 2).zip
/
MegaDisc 36 (1993-11)(MegaDisc Digital Publishing)(AU)(Disk 2 of 2).adf
/
ARexx
/
Chars
/
Chars_Doc
/
Chars_Doc
Wrap
Text File
|
1993-10-20
|
15KB
|
334 lines
ARexx : Designing Individual
Characters for Special Needs
by John Collett
36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36
Introduction
An old and much-maligned BBC computer languishes in my basement, unused
since the day I got my Amiga. When I bought the BBC, what seems like a
lifetime ago, it was a serious contender in the field, and I never
regretted the purchase. Even now, I grudgingly concede, it had some
pretty nifty features. For example, I could easily, at any time,
design any new character I needed, assign it to an ASCII value in a
specified range above 128, and then use it by referring to it by its
ASCII value. The following is an account of an attempt to obtain a
similar facility on an Amiga.
Two programs and a data file
The exercise involved the writing of two ARexx programs which I have
called 'CharGrid' and 'CharsDemo'. The main component of the first,
as its name implies, is a grid of 8 * 8 cells which represent the
lines and pixels of a character. Each cell can be switched to 'on' -
shaded in - by a mouse click, or equally easily switched off.
The second program as it stands simply displays a few examples, but its
main functions could readily be used in any other program in which
special characters are needed. Communication between 'CharGrid' and
any subsequent application using the 'CharsDemo' functions is via a
character storage file. The small sample file here called 'chars'
holds definitions for 20 or so characters, but there is virtually no
limit to its possible size, and no restrictions on its name.
If you run 'CharsDemo' (which it might be a good idea to do first,
before you try defining characters of your own), you will see that it
is anything but blindingly fast in its operation. A 'Rexx Plus'
compiled version is noticeably faster, though still not as fast as I
would like it to be, probably because I
never
have what you
could call a smooth run when compiling with 'Rexx Plus'. I've still
got a lot of learning to do there.
How 'CharsDemo' and 'CharGrid' work
The major tasks of 'CharGrid' are to enable a user to design a
character, and then to store labels and numbers in a file.
To make it easy to adjust pixels at the design stage, a grid is used
to represent a character at 8 times its normal size.
·······* 1
An 'on' pixel is here shown as '*'.
······*· 2
A value can be given to each pixel in
·····*·· 4
a row, expressed as 2 to the power of
····*··· 8
the column number, counting columns
···*···· 16
from the right, 0 to 7. The numbers
··*····· 32
shown here range from 1 ( = 2**0) to
·*······ 64
128 ( = 2**7).
*······· 128
'**' is the ARexx exponentiation symbol.
·······* 1
If more than one pixel in a row is 'on',
······** 3
their values can be summed. In the
·····*** 7
second row, 1 + 2 = 3, and so on.
····**** 15
Any number between 1 and 255 can
···***** 31
uniquely define the state of all the
··****** 63
pixels in a given row.
·******* 127
******** 255
···**··· 24
A character '1' which differs from the
··***··· 56
standard could be defined as shown
·****··· 120
here. The set of numbers, 24 to 126,
···**··· 24
can be stored and used later to
···**··· 24
recreate the character as displayed.
···**··· 24
···**··· 24
·******· 126
The three sample shapes we have just looked at could be stored thus,
with a label for the purposes of identification, and eight numeric
values in each case :
diag,1,2,4,8,16,32,64,128
triang,1,3,7,15,31,63,127,255
one,24,56,120,24,24,24,24,126
The tasks of the main functions in 'CharsDemo' are to lift required
sets of data out of the file and, line by line, to draw up characters
according to the stored pixel values.
A closer look at 'CharGrid'
In a 'rexxarplib' window opened for the purpose, a grid and a column
of gadgets ('Show' to 'Quit') are displayed :
_______________
|_|_|_|_|_|_|_|_|
0 Show -->
|_|_|_|_|_|_|_|_|
0 Save
|_|_|_|_|_|_|_|_|
0 Clear
|_|_|_|_|_|_|_|_|
0 Load
|_|_|_|_|_|_|_|_|
0 Help
|_|_|_|_|_|_|_|_|
0 Quit
|_|_|_|_|_|_|_|_|
0
|_|_|_|_|_|_|_|_|
0
A mouse click within the grid toggles a cell on/off, and the
character shape is built up as you make successive 'on' clicks. The
column of row totals, here shown as zeros, is constantly updated,
just to provide visual confirmation of what's going on. (No value is
shown for any row until one of its cells has been activated.)
If at any time you want to see what your new character is going to
look like when used, click on 'Show', and it will appear next to the
'-->', at its real size, one-eighth of that of the grid. The process
is similar to that used by the 'CharsDemo' program when user-defined
characters are actually used. It is a bit complicated, and takes a
second or two to do its job. We'll have a closer look at one or
two of the details later on.
When you want to save a character, click on 'Save'. When you want to
edit a previously saved character, click on 'Load'. If this is the
first 'Save' or 'Load' in the current session, a file requester will
appear asking you to specify a file name. For saving, this will be
either an existing file to which new characters may be appended, or
the name of a new file which you wish to create. For loading, it
must, of course, be an existing file. Once the file is open (or
straightaway if it has been opened earlier), you are asked to provide a
label for the character which you wish to save or load. In 'Load',
assuming the data for the requested character exists, the relevant
cells of the grids are shaded in one after the other, and you can then
edit the design if you wish.
'Clear' clears the grid, 'Help' provides a list of brief reminders,
and 'Quit' exits the program.
Have a look at my file 'chars' to see the format of the entries I have
saved.
A closer look at 'CharsDemo'
For ages I have been using in ARexx a print-at function which takes
a piece of text and prints it at given x and y values.
That was the beginning of a much more complicated function in
'CharsDemo' which I have called 'Chart'. It first examines the text
which it is to print for the presence of any label markers { and }.
Between the braces is a character label, and when any labels in a line
of text have been located in the relevant file, the data required to
draw the character(s) in question is obtained from the same source.
Any unmarked text, not in braces, is printed in the usual way, and
then the required special characters are constructed at the indicated
position. For example, if we had defined as BigJ and BigK two
characters which looked something like a J and a K, then
call Chart(30,40,'Here is {BigJ} and here is {BigK}.')
would produce something like the following at position 30,40 :
Here is J and here is K.
'CharsDemo' simply gives a few examples, which include alpha, beta,
pi, chi, a couple of symbols from the International Phonetic Alphabet,
and a demo of how adjacent shapes can be made to look like a single
large character.
Applications of 'parse'
The 'CharsDemo' programs contains three examples of the use of the
powerful ARexx instruction 'parse', and some readers may be interested
in a closer look at them.
1
Removing {labels} from a line of text
If a line of {text} contains {labels} enclosed by {braces}, then those
labels can be extracted by using the '{' and the '}' alternately as
template markers, working along the line until it has all been parsed
out. Within a loop : "do until txt = '' ..... end", the following line
does the work :
parse var txt t1 '{' txt ; parse var txt t2 '}' txt
First half
Take the part of the variable called 'txt' which lies before the
'{', assign it to 't1', and assign the remainder of 'txt' to another
variable also called 'txt', thereby overwriting the original.
Second half
Do the same thing with the first part of the new 'txt', as far as the
'}', assigning it to 't2'.
As we go through the loop, all contents of braces are thus isolated.
In other coding not shown here a variable 'newtxt' is built up of the
pieces outside the braces, while the pieces inside the braces are
assigned to elements of the 'label. ' array. The position of each
special character insertion is recorded in 'pos.n'. It seems to work.
2
Finding each label in the data file
When we are looking through the 'chars' file to find the line of data
relating to a particular shape, the first part of each line, as far as
its first comma, needs to be examined. All lines are considered in
turn, the first element of each line being parsed out and compared with
the target label, until a match is found. In (I hope) plain English :
Do until 'found' is true, or the end of the file is reached.
Read in the next line of the file.
Isolate the part of the line up to but not including a comma.
The rest of the line is called 'parms' for later use if required.
Compare the first part with the target label.
Set 'found' to TRUE if they match.
In ARexx:
do until found | eof(cf)
t = readln(cf) ; parse var t lab ',' parms .
found = (lab = label.la)
end
3
Reading in the eight row values
The eight row values for the found character definition are then
parsed out of the line. You might expect this to be done in a loop,
like this :
do pa = 1 to 8
parse var parms a.pa parms .
end
But in fact I found that the following works slightly faster :
parse var parms a.1 ',' a.2 ',' a.3 ',' a.4 ',' a.5 ',',
a.6 ',' a.7 ',' a.8 .
Data conversion
In 'CharGrid' a constant record is kept of the state of all entries in
a set of compound variables of the form 'row.column.state' where
'row' and 'column' both range from 1 to 8 and 'state' is either 0 or 1.
(The actual stem and segment names in the program are more cryptic.)
The decimal values corresponding to each row are constantly updated and
displayed. Given a row of entries the 'states' of which can be
represented thus: 01001011, it can be converted into a more
convenient form by :
packed = 0
do col = 1 to 8
if row.column.state then packed = packed + 2**(8-column)
end
This should yield 75 (reading 01001011 from right to left, 1 + 2 + 8 +
64).
The reverse process is required when a set of eight decimal values is
read in from the data file in the 'load' option in 'CharGrid', and
when 'CharsDemo' obtains those values to display a character. If the
array 'a.' is the set of decimal values, then the following patch
will convert them into sets of 0's and 1's (like converting the '75'
mentioned a few lines ago back into '01001011'.)
do j = 1 to 8
if a.j = 0 then iterate /* All zeros; no point going on */
octet = c2b(d2c(a.j))
do bit = 1 to 8
If we actually want to draw a real-size character at position
col,row, we then use :
if substr(octet,bit,1) then do
call Move(HO,col+bit,row); call Draw(HO,col+bit,row); end
end
But if we are using the 'load' option to fill in the cells of the large
grid, then we need :
if substr(octet,bit,1) then call DoCell(bit,j)
end
end
See 'CharGrid' for details of the DoCell() function.
Note how a single pixel is painted in. You call Move() to go to the
point in question, and then call Draw()
with the same x and y
parameters
. It just draws to where it is, and a single point is
produced.
Also of interest is the assignment to 'octet'. Take the value '75', for
example, and see how it behaves in 'c2b(d2c(75))'. If you want to
clarify the process, try these three stages in a CLI window :
rx 'say d2c(75)' --> K
rx 'say c2b(K)' --> 01001011
rx 'say c2b(d2c(75))' --> 01001011
What else could be done?
The demo includes one large character made up of two adjacent pieces,
giving a shape which is 16 pixels wide. I have played around with
things like _ _ _
|- and -| with varying numbers of - in between,
and produced all sorts of gates and fences, with a lot more detail than
shown here. You can also have characters vertically adjacent to
make towers, spires, or whatever. In a wild few moments I designed
four quarters of a flower, arranged them together like this /\
and then used Flood to give them some colour. \/
There are all sorts of possibilities.
If you want to be really adventurous, the grid in 'CharGrid' could be
made wider : 10, 12, 14, even 16 cells. I tried it with 12, and it
worked, though
rather
slowly, and it did need a lot of adjustments
to be made to the program - so much so that I dropped an earlier idea
of having grid size as an adjustable variable in the program.
Hamilton, N.Z. September, 1991
------------------------------------
36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36